﻿using System;
using System.Collections.Generic;
using System.IO;

namespace Aeon.Emulator
{
    /// <summary>
    /// Implements a null IO port which stores a single value.
    /// </summary>
    internal sealed class DefaultPortHandler : IInputPort, IOutputPort
    {
        #region Private Fields
        private SortedList<int, ushort> values = new SortedList<int, ushort>();
        #endregion

        #region Constructors
        /// <summary>
        /// Initializes a new instance of the DefaultPortHandler class.
        /// </summary>
        /// <param name="port">Port to handle.</param>
        public DefaultPortHandler()
        {
        }
        #endregion

        #region IInputPort Members
        /// <summary>
        /// Gets the ports handled.
        /// </summary>
        public IEnumerable<int> InputPorts
        {
            get
            {
                return values.Keys;
            }
        }
        /// <summary>
        /// Reads the current value of the port as a byte.
        /// </summary>
        /// <param name="port">Port to read.</param>
        /// <returns>Current value of the port as a byte.</returns>
        public byte ReadByte(int port)
        {
            //ushort value;
            //if(values.TryGetValue(port, out value))
            //    return (byte)value;
            //else
                return 0xFF;
        }
        /// <summary>
        /// Reads the current value of the port as a word.
        /// </summary>
        /// <param name="port">Port to read.</param>
        /// <returns>Current value of the port as a word.</returns>
        public ushort ReadWord(int port)
        {
            //ushort value;
            //if(values.TryGetValue(port, out value))
            //    return value;
            //else
                return 0xFFFF;
        }
        #endregion

        #region IOutputPort Members
        /// <summary>
        /// Gets the ports handled.
        /// </summary>
        public IEnumerable<int> OutputPorts
        {
            get
            {
                return values.Keys;
            }
        }
        /// <summary>
        /// Writes a byte to the port.
        /// </summary>
        /// <param name="port">Port to write to.</param>
        /// <param name="value">Byte value to write to the port.</param>
        public void WriteByte(int port, byte value)
        {
            values[port] = value;
        }
        /// <summary>
        /// Writes a word to the port.
        /// </summary>
        /// <param name="port">Port to write to.</param>
        /// <param name="value">Word value to write to the port.</param>
        public void WriteWord(int port, ushort value)
        {
            values[port] = value;
        }
        #endregion

        #region IVirtualDevice Members
        void IVirtualDevice.Pause()
        {
        }
        void IVirtualDevice.Resume()
        {
        }
        /// <summary>
        /// Invoked when the virtual device has been added to a VirtualMachine.
        /// </summary>
        /// <param name="vm">VirtualMachine which owns the device.</param>
        void IVirtualDevice.DeviceRegistered(VirtualMachine vm)
        {
        }
        /// <summary>
        /// Invoked when the device should save its current state to a <see cref="System.IO.Stream"/>.
        /// </summary>
        /// <param name="destination"><see cref="System.IO.Stream"/> to which the state is saved.</param>
        void IVirtualDevice.SaveCurrentState(Stream destination)
        {
            var writer = new BinaryWriter(destination);
            writer.Write(this.values.Count);
            foreach(var pair in this.values)
            {
                writer.Write(pair.Key);
                writer.Write(pair.Value);
            }
        }
        /// <summary>
        /// Invoked when the device should restore its state from a <see cref="System.IO.Stream"/>.
        /// </summary>
        /// <param name="source"><see cref="System.IO.Stream"/> from which the state is restored.</param>
        void IVirtualDevice.RestoreState(Stream source)
        {
            var reader = new BinaryReader(source);
            int count = reader.ReadInt32();
            this.values.Clear();
            for(int i = 0; i < count; i++)
            {
                int port = reader.ReadInt32();
                ushort value = reader.ReadUInt16();
                this.values[port] = value;
            }
        }
        #endregion

        #region IDisposable Members
        void IDisposable.Dispose()
        {
        }
        #endregion
    }
}
